package com.example.demo.service.impl;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.example.demo.exception.ServiceException;
import com.example.demo.mapper.SysDeptMapper;
import com.example.demo.mapper.SysRoleMapper;
import com.example.demo.mapper.SysUserMapper;
import com.example.demo.mapper.SysUserRoleMapper;
import com.example.demo.model.converter.SysUserConverter;
import com.example.demo.model.core.PageVo;
import com.example.demo.model.entity.SysDept;
import com.example.demo.model.entity.SysRole;
import com.example.demo.model.entity.SysUser;
import com.example.demo.model.entity.SysUserRole;
import com.example.demo.model.form.PasswordForm;
import com.example.demo.model.form.UserForm;
import com.example.demo.model.form.UserPasswordForm;
import com.example.demo.model.form.UserProfileForm;
import com.example.demo.model.query.UserQuery;
import com.example.demo.model.vo.LoginUserVO;
import com.example.demo.model.vo.UserProfileVO;
import com.example.demo.model.vo.UserVO;
import com.example.demo.security.model.SysUserDetails;
import com.example.demo.security.model.UserAuthCredentials;
import com.example.demo.security.token.TokenManager;
import com.example.demo.security.util.SecurityUtils;
import com.example.demo.service.SysRoleService;
import com.example.demo.service.SysUserService;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class SysUserServiceImpl implements SysUserService {

    @Autowired
    private SysUserConverter sysUserConverter;
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;
    @Autowired
    private SysRoleMapper sysRoleMapper;
    @Autowired
    private SysDeptMapper sysDeptMapper;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private TokenManager tokenManager;
    @Autowired
    private SysRoleService sysRoleService;

    @Override
    @Transactional
    public void add(UserForm form) {
        Assert.isFalse(sysUserMapper.selectCountByQuery(QueryWrapper.create().eq("username", form.getUsername())) > 0, "用户名已存在");

        SysUser entity = sysUserConverter.toEntity(form);
        entity.setPassword(passwordEncoder.encode("123456"));
        entity.setStatus(1);
        sysUserMapper.insert(entity);
        List<String> roleIds = form.getRoleIds();
        for (String roleId : roleIds) {
            SysUserRole sysUserRole = new SysUserRole();
            sysUserRole.setUserId(entity.getId());
            sysUserRole.setRoleId(roleId);
            sysUserRoleMapper.insert(sysUserRole);
        }
    }

    @Override
    @Transactional
    public void update(UserForm form) {
        Assert.isFalse(sysUserMapper.selectCountByQuery(QueryWrapper.create().eq("username", form.getUsername()).ne("id", form.getId())) > 0, "用户名已存在");

        SysUser entity = sysUserConverter.toEntity(form);
        sysUserMapper.update(entity);
        QueryWrapper wrapper = QueryWrapper.create().eq("user_id", entity.getId());
        sysUserRoleMapper.deleteByQuery(wrapper);
        List<String> roleIds = form.getRoleIds();
        for (String roleId : roleIds) {
            SysUserRole sysUserRole = new SysUserRole();
            sysUserRole.setUserId(entity.getId());
            sysUserRole.setRoleId(roleId);
            sysUserRoleMapper.insert(sysUserRole);
        }
    }

    @Override
    @Transactional
    public void delete(List<String> ids) {
        sysUserMapper.deleteBatchByIds(ids);
        QueryWrapper wrapper = QueryWrapper.create().in("user_id", ids);
        sysUserRoleMapper.deleteByQuery(wrapper);
    }

    @Override
    public PageVo<UserVO> page(UserQuery query) {
        QueryWrapper wrapper = QueryWrapper.create();
        if (StrUtil.isNotBlank(query.getUsername())) {
            wrapper.like("username", query.getUsername());
        }
        if (StrUtil.isNotBlank(query.getDeptId())) {
            wrapper.eq("dept_id", query.getDeptId());
        }
        Page<SysUser> page = sysUserMapper.paginate(query.getPageNum(), query.getPageSize(), wrapper);
        PageVo<SysUser> pageVo = new PageVo<>();
        pageVo.setList(page.getRecords());
        pageVo.setTotal(page.getTotalRow());
        return sysUserConverter.toPageVo(pageVo);
    }

    @Override
    public UserForm form(String id) {
        SysUser sysUser = sysUserMapper.selectOneById(id);
        Assert.notNull(sysUser,"用户不存在");
        List<String> roleIds = new ArrayList<>(getUserRoles(id));
        return sysUserConverter.toForm(sysUser, roleIds);
    }

    @Override
    public UserAuthCredentials getAuthCredentialsByUsername(String username) {
        QueryWrapper wrapper = QueryWrapper.create().eq("username", username);
        SysUser sysUser = sysUserMapper.selectOneByQuery(wrapper);
        if (sysUser == null) {
            return null;
        }
        Set<String> sysUserRoles = getUserRoles(sysUser.getId());
        return sysUserConverter.toUserAuthCredentials(sysUser, sysUserRoles);
    }

    @Override
    public LoginUserVO getLoginUser() {
        Optional<SysUserDetails> user = SecurityUtils.getUser();
        LoginUserVO loginUserVo = null;
        if (user.isPresent()) {
            SysUser sysUser = sysUserMapper.selectOneById(user.get().getUserId());
            Assert.notNull(sysUser,"用户不存在");
            Set<String> roles = this.getUserRoles(sysUser.getId());
            Set<String> perms = sysRoleService.getRolePermissions(roles);
            loginUserVo = sysUserConverter.toLoginUser(sysUser, roles, perms);
        }
        return loginUserVo;
    }

    @Override
    public UserProfileVO getUserProfile(String userId) {
        SysUser sysUser = sysUserMapper.selectOneById(userId);
        Assert.notNull(sysUser, "用户不存在");
        Set<String> roles = getUserRoles(userId);
        List<SysRole> sysRoles = sysRoleMapper
                .selectListByQuery(QueryWrapper.create().select("id", "name").in("id", roles));
        SysDept sysDept = null;
        if (StrUtil.isNotBlank(sysUser.getDeptId())) {
            sysDept = sysDeptMapper.selectOneById(sysUser.getDeptId());
        }
        return sysUserConverter.toUserProfileVO(sysUser,
                sysRoles.stream().map(SysRole::getName).collect(Collectors.joining(",")),
                sysDept != null ? sysDept.getName() : "");
    }

    @Override
    public void updateUserProfile(String userId, UserProfileForm form) {
        SysUser sysUser = sysUserMapper.selectOneById(userId);
        Assert.notNull(sysUser, "用户不存在");
        sysUser.setNickName(form.getNickname());
        sysUser.setGender(form.getGender());
        sysUser.setPhone(form.getPhone());
        sysUser.setEmail(form.getEmail());
        sysUser.setAvatar(form.getAvatar());
        sysUserMapper.update(sysUser);
    }

    @Override
    public void updateUserPassword(String userId, PasswordForm form) {
        SysUser sysUser = sysUserMapper.selectOneById(userId);
        Assert.notNull(sysUser, "用户不存在");
        String oldPassword = form.getOldPassword();
        // 校验原密码
        if (!passwordEncoder.matches(oldPassword, sysUser.getPassword())) {
            throw new ServiceException("原密码错误");
        }
        // 新旧密码不能相同
        if (passwordEncoder.matches(form.getNewPassword(), sysUser.getPassword())) {
            throw new ServiceException("新密码不能与原密码相同");
        }

        // 判断新密码和确认密码是否一致
        if (!form.getNewPassword().equals(form.getConfirmPassword())) {
            throw new ServiceException("新密码和确认密码不一致");
        }
        sysUser.setPassword(passwordEncoder.encode(form.getNewPassword()));
        sysUserMapper.update(sysUser);
        String accessToken = SecurityUtils.getTokenFromRequest();
        tokenManager.invalidateToken(accessToken);
    }

    @Override
    public void updateUserPassword(UserPasswordForm form) {
        SysUser sysUser = sysUserMapper.selectOneById(form.getUserId());
        Assert.notNull(sysUser, "用户不存在");
        sysUser.setPassword(passwordEncoder.encode(form.getPassword()));
        sysUserMapper.update(sysUser);
    }


    private Set<String> getUserRoles(String userId) {
        QueryWrapper wrapper = QueryWrapper.create().eq("user_id", userId);
        List<SysUserRole> sysUserRoles = sysUserRoleMapper.selectListByQuery(wrapper);
        return sysUserRoles.stream().map(SysUserRole::getRoleId).collect(Collectors.toSet());
    }

}
